<?php
/* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 textwidth=150 number: */

/**
 * Classe Pessoa
 *
 * ...
 *
 * PHP versão 5
 *
 * LICENÇA: Este arquivo fonte esta sob o termos da licença MIT.
 *
 * @package   scuf.model
 * @author    Rodrigo Casara <rodrigocasara@gmail.com>
 * @copyright 2012 Rodrigo Casara
 * @license   MIT License (http://www.opensource.org/licenses/mit-license.php)
 * @version   SVN: $Id$
 * @link
 * @since     SCUF(tm) v 1.0.0
 */

App::uses('AppModel', 'Model');
App::uses('Utils', 'Lib');

/**
 * Pessoa
 *
 * {@inheritdoc}
 */
class Pessoa extends AppModel {

  /**
   * Regras de validação
   *
   * @var array
   */
  public $validate = array(
    'nome' => array(
      'obrigatorio' => array(
        'rule' => array('notempty'),
        'message' => 'Obrigatório'
      ),
      'min_caracteres' => array(
        'rule' => array('minLength', 3),
        'message' => 'O nome deve conter no mínimo 3 caracteres'
      ),
      'caracteres_validos' => array(
        'rule' => array('caracteresValidos', '/^\D{3,}$/i'),
        'message' => 'Caracteres inválidos. Somente letras e espaços são permitidos.'
      ),
    ),
    'sexo' => array(
      'obrigatorio' => array(
        'rule' => array('notempty'),
        'message' => 'Obrigatório'
      ),
      'lista' => array(
        'rule' => array('inList', array('F', 'M')),
        'message' => 'Sexo inválido'
      )
    ),
    'data_nascimento' => array(
      'obrigatorio' => array(
        'rule' => array('notEmpty'),
        'message' => 'Obrigatório'
      ),
      'date' => array(
        'rule' => array('date'),
        'message' => 'Data inválida'
      )
    ),
    'email' => array(
      'obrigatorio' => array(
         'rule' => array('notEmpty'),
        'message' => 'Obrigatório'
      ),
      'email' => array(
        'rule' => array('email', true), // true no segundo parâmetro, para verificar o host do endereço de e-mail.
        'message' => 'E-mail inválido'
      )
    ),
    'senha' => array(
      'obrigatorio' => array(
        'rule' => array('notempty'),
        'message' => 'Obrigatório'
      ),
      'min_caracteres' => array(
        'rule' => array('minLength', 6),
        'message' => 'A senha deve conter no mínimo 6 caracteres'
      ),
      'confirmar_senha' => array(
        'rule' => array('confirmarSenha'),
        'message' => 'As senhas não conferem'
      )
    ),
    'municipio_id' => array(
      'obrigatorio' => array(
        'rule' => array('notempty'),
        'message' => 'Obrigatório'
      ),
      'numerico' => array(
        'rule' => array('numeric'),
        'message' => 'Município inválido'
      ),
    ),
    'telefone_residencial' => array(
      'telefone' => array(
        'rule' => array('phone', null, 'us'),
        'message' => 'Número de telefone inválido',
        'allowEmpty' => true
      )
    ),
    'telefone_celular' => array(
      'telefone' => array(
        'rule' => array('phone', null, 'us'),
        'message' => 'Número de telefone inválido',
        'allowEmpty' => true
      )
    ),
    'fotografia' => array(
      'erros_de_upload' => array(
        'rule' => array('errosDeUpload')
        // 'message' será setado pela função de validação em caso de erro.
      ),
      'image' => array(
        'rule' => array('extension', array('jpeg', 'jpg', 'png')),
        'message' => 'Arquivo inválido'
      ),
      'tamanho_do_arquivo' => array(
        'rule' => array('tamanhoDoArquivo', '300k'),
        'message' => 'Arquivo com tamanho superior a 300 KB não permitido'
      ),
      'arquivo_valido' => array(
        'rule' => array('arquivoValido'),
        'message' => 'Arquivo inválido'
      ),
      'dimensoes_em_pixels' => array(
        'rule' => array('dimensoesEmPixels', 300, 400, false),
        'message' => 'A resolução não pode ultrapassar 300 pixels de largura por 400 pixels de altura'
      )
    )
  );

  /**
   * Associações "pertence à".
   *
   * @var array
   */
  public $belongsTo = array(
    'Municipio' => array(
      'className' => 'Municipio',
      'foreignKey' => 'municipio_id',
      'conditions' => '',
      'fields' => '',
      'order' => ''
    )
  );

  // CakePHP Callbacks {{{

  /**
   * (non-PHPdoc)
   * @see Model::beforeValidate()
   */
  public function beforeValidate() {
    // Formata a data de nascimento no formato americano YYYY-MM-DD {{{
    if (isset($this->data[$this->alias]['data_nascimento'])) {
      $this->data[$this->alias]['data_nascimento'] = Utils::converterDataDMYParaSQL($this->data[$this->alias]['data_nascimento']);
    }
    //}}}
    // Removerespaços extras no início e no fim {{{
    if (isset($this->data[$this->alias]['nome'])) { $this->
      $this->data[$this->alias]['nome'] = trim($this->data[$this->alias]['nome']);
    }
    //}}}
    // Remover máscaras {{{
    if (isset($this->data[$this->alias]['telefone_residencial'])) {
      $this->data[$this->alias]['telefone_residencial'] = mb_ereg_replace("[^0-9]", "", $this->data[$this->alias]['telefone_residencial']);
    }
    if (isset($this->data[$this->alias]['telefone_celular'])) {
      $this->data[$this->alias]['telefone_celular'] = mb_ereg_replace("[^0-9]", "", $this->data[$this->alias]['telefone_celular']);
    }
    //}}}
    // TODO: verificar município não cadastrado (validação de chaves estrangeiras). {{{
    //}}}
    // Pré-validar e-mail (índice único) {{{
    if (!$this->isUnique(array('email'))) {
      $this->validationErrors['email'] = array('Este e-mail já está cadastrado, informe outro');
      $okEmail = false;
    } else {
      $okEmail = true;
    }
    //}}}
    // Pré-validação de telefone residêncial e telefone celular {{{
    $telefoneResidencialNaoInformado = !isset($this->data[$this->alias]['telefone_residencial'])
                                     || empty($this->data[$this->alias]['telefone_residencial']);
    $telefoneCelularNaoInformado = !isset($this->data[$this->alias]['telefone_celular']) || empty($this->data[$this->alias]['telefone_celular']);
    if ($telefoneResidencialNaoInformado && $telefoneCelularNaoInformado) {
      if ($telefoneResidencialNaoInformado) {
        $this->validationErrors['telefone_residencial'] = array('Obrigatório caso não possua telefone celular');
        // TODO: forma correta. Criar a regra de validação 'obrigatorio_um_telefone' para o campo.
        //$this->invalidate('telefone_residencial', 'obrigatorio_um_telefone');
      }
      if ($telefoneCelularNaoInformado) {
        $this->validationErrors['telefone_celular'] = array('Obrigatório caso não possua telefone residêncial');
        // TODO: forma correta. Criar a regra de validação 'obrigatorio_um_telefone' para o campo.
        //$this->invalidate('telefone_celular', 'obrigatorio_um_telefone');
      }
      $okTelefones = false;
    } else {
      $okTelefones = true;
    }
    //}}}
    return $okEmail && $okTelefones;
  }

  /**
   * (non-PHPdoc)
   * @see Model::beforeSave()
   */
  public function beforeSave() {
    if (!isset($this->data[$this->alias]['id'])) {
      $sql = "SELECT nextval('pessoas_id_seq'::regclass)";
      $id = $this->query($sql);
      $this->data[$this->alias]['id'] = $id[0][0]["nextval"];
    }
    if (isset($this->data[$this->alias]['nome'])) {
      $this->data[$this->alias]['nome'] = Utils::formatarNomeProprio($this->data[$this->alias]['nome']);
    }
    if (isset($this->data[$this->alias]['sexo'])) {
      $this->data[$this->alias]['sexo'] = strtoupper($this->data[$this->alias]['sexo']);
    }
    if (isset($this->data[$this->alias]['senha'])) {
      $this->data[$this->alias]['senha'] = AuthComponent::password($this->data[$this->alias]['senha']);
    }
    if (isset($this->data[$this->alias]['fotografia'])) {
      $ext = pathinfo($this->data[$this->alias]['fotografia']['name'], PATHINFO_EXTENSION);
      $this->data[$this->alias]['fotografia']['name'] = $this->data[$this->alias]['id'] . "." . strtolower($ext);
      $destino = Configure::read("DiretorioDeFotografiasDasPessoas") . DS . $this->data[$this->alias]['fotografia']['name'];
      if (!@move_uploaded_file($this->data[$this->alias]['fotografia']['tmp_name'], $destino)) {
        // TODO: Melhorar a mensagem de erro no campo, analizar se é nessário registrar no log e avisar o admin por e-mail.
        $this->validationErrors['fotografia'] = array('Erro no upload');
        // TODO: forma correta. Criar a regra de validação 'erro_upload' para o campo.
        //$this->invalidate('fotografia', 'erro_upload');
        return false;
      }
      @chmod($destino, 0644);
      $this->data[$this->alias]['fotografia'] = $this->data[$this->alias]['fotografia']['name'];
    }
    return true;
  }

  //}}}

  // Métodos customizados de validação {{{

  public function caracteresValidos($dados, $padrao) {
    if (!preg_match($padrao, $dados['nome'])) {
      return false;
    }
    return true;
  }

  public function confirmarSenha($dados) {
    if ($dados['senha'] === $this->data[$this->alias]['confirmar_senha']) {
      return true;
    }
    return true;
  }

  public function errosDeUpload($dados) {
    $mensagensDeErro = array(
      UPLOAD_ERR_INI_SIZE   => 'O arquivo enviado excede a diretiva upload_max_filesize em php.ini.',
      UPLOAD_ERR_FORM_SIZE  => 'O arquivo enviado excede o tamanho em MAX_FILE_SIZE que foi especificado no formulário HTML.',
      UPLOAD_ERR_PARTIAL    => 'O arquivo foi apenas parcialmente carregado.',
      UPLOAD_ERR_NO_TMP_DIR => 'Faltando uma pasta temporária.',
      UPLOAD_ERR_CANT_WRITE => 'Falha ao gravar arquivo em disco.',
      UPLOAD_ERR_EXTENSION  => 'Arquivo de upload parou por extensão.'
    );

    if (   $dados['fotografia']['error'] !== UPLOAD_ERR_OK
        && $dados['fotografia']['error'] !== UPLOAD_ERR_NO_FILE
    ) {
      $this->validationErrors['fotografia'] = array($mensagensDeErro[$dados['fotografia']['error']]);
      // TODO: forma correta. Criar uma regra de validação para cada tipo de erro tratado pelo método, passando como parâmetro o tipo de erro detectado.
      //$this->invalidate('fotografia', '<tipo>');
      return false;
    }
    return true;
  }

  public function tamanhoDoArquivo($dados, $tamanho) {
    $tamanho = Utils::obterTamanhoEmBytes($tamanho);
    if ($dados['fotografia']['size'] > $tamanho) {
      return false;
    }
    return true;
  }

  public function arquivoValido($dados) {
    $dimensoes = getimagesize($dados['fotografia']['tmp_name']);
    switch ($dimensoes[2]) {
      case IMAGETYPE_JPEG:
        $imagem = @imagecreatefromjpeg($dados['fotografia']['tmp_name']);
        break;
      case IMAGETYPE_PNG:
        $imagem = @imagecreatefrompng($dados['fotografia']['tmp_name']);
        break;
      default:
        $imagem = false;
        break;
    }
    if (!$imagem) {
      return false;
    }
    return true;
  }

  public function dimensoesEmPixels($dados, $largura, $altura, $valoresExatos = false) {
    $dimensoes = getimagesize($dados['fotografia']['tmp_name']);
    if (!$dimensoes[0] || !$dimensoes[1]) {
      return false;
    } elseif ($valoresExatos === false || $valoresExatos === null) {
      if ($dimensoes[0] > $largura || $dimensoes[1] > $altura) {
        return false;
      }
    } elseif ($dimensoes[0] !== $largura || $dimensoes[1] !== $altura) {
      return false;
    }
    return true;
  }

  //}}}

}
?>